package cn.jsxz.common.utils.NumberUtil;

import java.math.BigDecimal;

/**
 * BigDecimal 运算工具类
 */
public class MathUtil {


    /**
     * 默认的数据精度
     */
    private static final int DEF_SCALE = 2;

    /**
     * 默认的精度取舍方式(银行家算法)
     */
    private static final int DEF_ROUNDMODE = BigDecimal.ROUND_HALF_EVEN;

    //region 各种加法运算

    /**
     * @title 精确加法运算 BigDecimal
     */
    public static BigDecimal add(BigDecimal v1, BigDecimal v2) {
        if (null == v1) v1 = BigDecimal.ZERO;
        if (null == v2) v2 = BigDecimal.ZERO;
        return v1.add(v2);
    }

    /**
     * @title 精确加法运算 String
     */
    public static String add(String v1, String v2) {
        if (isBlank(v1)) v1 = "0";
        if (isBlank(v2)) v2 = "0";
        return String.valueOf(add(new BigDecimal(v1.trim()), new BigDecimal(v2.trim())));
    }

    /**
     * @title 相对精确加法运算 保留2位小数 BigDecimal
     */
    public static BigDecimal addScale2Dec(BigDecimal v1, BigDecimal v2) {
        return scale2Dec(add(v1, v2));
    }

    /**
     * @title 相对精确加法运算 保留2位小数 String
     */
    public static String addScale2Str(BigDecimal v1, BigDecimal v2) {
        return scale2Str(add(v1, v2));
    }
    //endregion

    //region 各种减法运算

    /**
     * @title 精确减法运算 BigDecimal
     */
    public static BigDecimal subtract(BigDecimal v1, BigDecimal v2) {
        if (null == v1) return BigDecimal.ZERO;
        if (null == v2) return v1;
        return v1.subtract(v2);
    }

    /**
     * @title 精确减法运算 String
     */
    public static String subtract(String v1, String v2) {
        if (isBlank(v1)) return "0";
        if (isBlank(v2)) return v1;
        return String.valueOf(subtract(new BigDecimal(v1.trim()), new BigDecimal(v2.trim())));
    }

    /**
     * @title 相对精确减法运算 保留2为小数 BigDecimal
     */
    public static BigDecimal subtractScale2Dec(BigDecimal v1, BigDecimal v2) {
        return scale2Dec(subtract(v1, v2));
    }

    /**
     * @title 相对精确减法运算 保留2为小数 BigDecimal
     */
    public static BigDecimal subtractScale2Dec(BigDecimal v1, BigDecimal... valList) {
        if (null == v1) v1 = BigDecimal.ZERO;
        if (null == valList || valList.length == 0) return v1;
        for (BigDecimal val : valList) {
            if (null != val) {
                v1 = subtract(v1, val);
            }
        }
        return scale2Dec(v1);
    }

    /**
     * @title 相对精确减法运算 保留2位小数 String
     */
    public static String subtractScale2Str(BigDecimal v1, BigDecimal v2) {
        return scale2Str(subtract(v1, v2));
    }
    //endregion

    //region 各种乘法运算

    /**
     * @title 精确乘法运算 BigDecimal
     */
    public static BigDecimal multiply(BigDecimal v1, BigDecimal v2) {
        if (null == v1 && null == v2) return BigDecimal.ZERO;
        if (null == v1) v1 = BigDecimal.ONE;
        if (null == v2) v2 = BigDecimal.ONE;
        return v1.multiply(v2);
    }

    /**
     * @title 精确乘法运算 String
     */
    public static String multiply(String v1, String v2) {
        if (isBlank(v1) && isBlank(v2)) return "0";
        if (isBlank(v1)) v1 = "1";
        if (isBlank(v2)) v2 = "1";
        return String.valueOf(multiply(new BigDecimal(v1.trim()), new BigDecimal(v2.trim())));
    }

    /**
     * @title 相对精确乘法运算 保留2位小数 BigDecimal
     */
    public static BigDecimal multiplyScale2Dec(BigDecimal v1, BigDecimal v2) {
        return scale2Dec(multiply(v1, v2));
    }

    /**
     * @title 相对精确乘法运算 保留2位小数 String
     */
    public static String multiplyScale2Str(BigDecimal v1, BigDecimal v2) {
        return scale2Str(multiply(v1, v2));
    }
    //endregion

    //region 各种除法运算

    /**
     * @title 相对精确除法运算 BigDecimal
     */
    public static BigDecimal divide(BigDecimal v1, BigDecimal v2) {
        return divide(v1, v2, DEF_SCALE);
    }

    /**
     * @title 相对精确除法运算 保留scale位小数 BigDecimal
     */
    public static BigDecimal divide(BigDecimal v1, BigDecimal v2, Integer scale) {
        if (null == v1 || null == v2) return BigDecimal.ZERO;
        if (null == scale || scale < 0) scale = DEF_SCALE;
        return v1.divide(v2, scale, DEF_ROUNDMODE);
    }

    /**
     * @title 相对精确除法运算 String
     */
    public static String divide(String v1, String v2) {
        return divide(v1, v2, DEF_SCALE);
    }

    /**
     * @title 相对精确除法运算 保留scale位小数 String
     */
    public static String divide(String v1, String v2, Integer scale) {
        if (isBlank(v1) || isBlank(v2)) return "0";
        if (null == scale || scale < 0) scale = DEF_SCALE;
        return String.valueOf(divide(new BigDecimal(v1.trim()), new BigDecimal(v2.trim()), scale));
    }
    //endregion

    //region 各种求和运算

    /**
     * @title 精确求和运算 , 忽略NULL BigDecimal
     */
    public static BigDecimal sum(BigDecimal v1, BigDecimal... valList) {
        if (null == v1) v1 = BigDecimal.ZERO;
        if (null == valList || valList.length == 0) return v1;
        for (BigDecimal val : valList) {
            if (null != val) {
                v1 = v1.add(val);
            }
        }
        return v1;
    }

    /**
     * @title 精确求和运算 , 忽略NULL String
     */
    public static String sum(String v1, String... valList) {
        if (isBlank(v1)) v1 = "0";
        if (null == valList || valList.length == 0) return v1;
        BigDecimal b1 = new BigDecimal(v1.trim());
        for (String val : valList) {
            if (!isBlank(val)) {
                b1 = add(b1, new BigDecimal(val.trim()));
            }
        }
        return String.valueOf(b1);
    }

    /**
     * @title 相对精确求和运算 , 保留2位小数 , 忽略NULL BigDecimal
     */
    public static BigDecimal sumScale2Dec(BigDecimal v1, BigDecimal... valList) {
        return scale2Dec(sum(v1, valList));
    }
    //endregion

    //region 平均数 最大/小数

    /**
     * @title 平均数 BigDecimal
     */
    public static BigDecimal avg(BigDecimal... valList) {
        if (null != valList && valList.length != 0) {
            return divide(sum(BigDecimal.ZERO, valList), new BigDecimal(valList.length));
        }
        return BigDecimal.ZERO;
    }

    /**
     * @title 平均数 String
     */
    public static String avg(String... valList) {
        if (null != valList && valList.length != 0) {
            return divide(sum("0", valList), String.valueOf(valList.length));
        }
        return "0";
    }

    /**
     * @title 最大值 BigDecimal
     */
    public static BigDecimal max(BigDecimal v1, BigDecimal... valList) {
        BigDecimal max = v1;
        if (null == valList || valList.length == 0) {
            return max;
        }
        for (BigDecimal val : valList) {
            if (null != val && val.compareTo(max) > 0) {
                max = val;
            }
        }
        return max;
    }

    /**
     * @title 最大值 String
     */
    public static String max(String v1, String... valList) {
        if (isBlank(v1)) {
            return null;
        }
        if (null == valList || valList.length == 0) {
            return v1;
        }
        BigDecimal maxBd = new BigDecimal(v1.trim());

        for (String val : valList) {
            if (!isBlank(val) && new BigDecimal(val).compareTo(maxBd) > 0) {
                maxBd = new BigDecimal(val);
            }
        }
        return String.valueOf(maxBd);
    }

    /**
     * @title 最大值 BigDecimal
     */
    public static BigDecimal maxArr(BigDecimal... valList) {
        return null == valList || valList.length == 0 ? null : max(valList[0], valList);
    }

    /**
     * @title 最大值 String
     */
    public static String maxArr(String... valList) {
        return null == valList || valList.length == 0 ? null : max(valList[0], valList);
    }

    /**
     * @title 最小值 BigDecimal
     */
    public static BigDecimal min(BigDecimal v1, BigDecimal... valList) {
        BigDecimal min = v1;
        if (null == valList || valList.length == 0) {
            return min;
        }
        for (BigDecimal val : valList) {
            if (null != val && val.compareTo(min) < 0) {
                min = val;
            }
        }
        return min;
    }

    /**
     * @title 最小值 String
     */
    public static String min(String v1, String... valList) {
        if (isBlank(v1)) {
            return null;
        }
        if (null == valList || valList.length == 0) {
            return v1;
        }
        BigDecimal minBd = new BigDecimal(v1.trim());

        for (String val : valList) {
            if (!isBlank(val) && new BigDecimal(val).compareTo(minBd) < 0) {
                minBd = new BigDecimal(val);
            }
        }
        return String.valueOf(minBd);
    }

    /**
     * @title 最小值 BigDecimal
     */
    public static BigDecimal minArr(BigDecimal... valList) {
        return null == valList || valList.length == 0 ? null : min(valList[0], valList);
    }

    /**
     * @title 最小值 String
     */
    public static String minArr(String... valList) {
        return null == valList || valList.length == 0 ? null : min(valList[0], valList);
    }
    //endregion

    //region 比较大小

    /**
     * @title val1 < val2 , 任何一个为null则返回false
     */
    public static boolean lessThan(BigDecimal val1, BigDecimal val2) {
        return isNoneNull(val1, val2) && val1.compareTo(val2) < 0;
    }

    /**
     * @title val1 <= val2 , 任何一个为null则返回false
     */
    public static boolean lessThanOrEqual(BigDecimal val1, BigDecimal val2) {
        return isNoneNull(val1, val2) && val1.compareTo(val2) <= 0;
    }

    /**
     * @title val1 > val2 , 任何一个为null则返回false
     */
    public static boolean moreThan(BigDecimal val1, BigDecimal val2) {
        return isNoneNull(val1, val2) && val1.compareTo(val2) > 0;
    }

    /**
     * @title val1 >= val2 , 任何一个为null则返回false
     */
    public static boolean moreThanOrEqual(BigDecimal val1, BigDecimal val2) {
        return isNoneNull(val1, val2) && val1.compareTo(val2) >= 0;
    }

    /**
     * @title val1 = val2 , 任何一个为null则返回false
     */
    public static boolean equalTo(BigDecimal val1, BigDecimal val2) {
        return isNoneNull(val1, val2) && val1.compareTo(val2) == 0;
    }
    //endregion

    //region 各种转换输出

    /**
     * @title 常规BigDecimal , 保留2位小数
     */
    public static BigDecimal scale2Dec(BigDecimal value) {
        return null == value ? null : value.setScale(DEF_SCALE, DEF_ROUNDMODE);
    }

    /**
     * @title 原生数值
     */
    public static String str(BigDecimal value) {
        return null == value ? "" : value.toString();
    }

    /**
     * @title 整数
     */
    public static String intBigDecimal(BigDecimal value) {
        return null == value ? "" : value.intValue() + "";
    }

    /**
     * @title 常规字符串 , 保留2位小数 , 默认""
     */
    public static String scale2Str(BigDecimal value) {
        return null == value ? "" : value.setScale(DEF_SCALE, DEF_ROUNDMODE).toString();
    }

    /**
     * @title 常规字符串 , 保留2位小数 , 默认0
     */
    public static String normalBigDecimalDefZero(BigDecimal value) {
        return null == value ? "0" : value.setScale(DEF_SCALE, DEF_ROUNDMODE).toString();
    }

    /**
     * @title 带百分号的字符串
     */
    public static String scale2Percentage(BigDecimal value) {
        return null == value ? "" : value.setScale(DEF_SCALE, DEF_ROUNDMODE).toString() + "%";
    }
    //endregion

    //region 自身判断 , 不依赖第三方

    /**
     * @title 判断字符串是否为空(不依赖第三方)
     */
    private static boolean isBlank(String str) {
        return null == str || str.trim().length() == 0;
    }

    /**
     * 校验一组对象是否全是非null值 , 有任意一个null则返回false
     */
    private static boolean isNoneNull(final Object... objects) {
        if (null == objects || objects.length == 0) {
            return true;
        }
        for (final Object object : objects) {
            if (null == object) {
                return false;
            }
        }
        return true;
    }
}
